#include "staticgesture.h"
#include "eventmanager.h"
#include "staticbeginevent.h"
#include "staticendevent.h"

#include <QTemporaryFile>
#include <QTextStream>
#include <QStringList>
#include <iostream>

using namespace mlgesture;
using namespace std;
using namespace cv;

StaticGesture::StaticGesture(const QString &model_file, const QString &scale_factors_file, const QString &labels_file,
			  int hands_num) throw (HandGestureException) {

	QTemporaryFile svm_tmp;
	svm_tmp.open();
	svm_tmp.close();
	QFile::copy(model_file, svm_tmp.fileName());
	svmModel_ = svm_load_model(model_file.toAscii());
	if (!svmModel_)
		throw HandGestureException("Cannot load static gestures model");
	QFile data_qfile(labels_file);
	data_qfile.open(QIODevice::ReadOnly | QIODevice::Text);
	if (!data_qfile.isOpen())
		throw HandGestureException(("Cannot open " + labels_file + " file").toStdString());
	QTextStream in_data(&data_qfile);
	QString line = in_data.readLine();
	while (!line.isNull()) {
		QStringList lists = line.split(" ");
		if (lists.size() != 2)
			throw HandGestureException("Bad labels file structure");
		bool ok;
		int tmp_id = lists[1].toInt(&ok);
		if (!ok)
			throw HandGestureException("Bad labels file structure");
		staticLabelsData_[tmp_id] = lists[0];
		line = in_data.readLine();
	}
	data_qfile.close();

	data_qfile.setFileName(scale_factors_file);
	data_qfile.open(QIODevice::ReadOnly | QIODevice::Text);
	if (!data_qfile.isOpen())
		throw HandGestureException(("Cannot open " + scale_factors_file + " file").toStdString());
	in_data.setDevice(&data_qfile);
	line = in_data.readLine();
	int scale_id = 0;
	while (!line.isNull()) {
		QStringList lists = line.split(" ");
		if (lists.size() != 2)
			throw HandGestureException("Bad scale factors file structure");
		bool ok1, ok2;
		double tmp_id1 = lists[0].toDouble(&ok1);
		double tmp_id2 = lists[1].toDouble(&ok2);
		if (!ok1 || !ok2)
			throw HandGestureException("Bad scale factors file structure");
		minScaleFactors_[scale_id] = tmp_id1;
		maxScaleFactors_[scale_id] = tmp_id2;
		scale_id++;
		line = in_data.readLine();
	}
	if (scale_id != 7)
		throw HandGestureException("Bad scale factors file structure");
	data_qfile.close();

	staticGestures_.resize(hands_num);
}

StaticGesture::~StaticGesture() {
	if (!svmModel_)
		svm_free_model_content(svmModel_);
}

const std::vector<int>& StaticGesture::getStaticGestures() const throw (HandGestureException) {
	return staticGestures_;
}

void StaticGesture::proccess(const vector<Mat> &shape) {
	StaticBeginEvent *begin_event;
	StaticEndEvent *end_event;
	int* svm_labels = new int[staticLabelsData_.size()];
	double* pred_prob = new double[staticLabelsData_.size()];
	svm_get_labels(svmModel_, svm_labels);
	const int cols = 7;
	for (size_t i=0; i<staticGestures_.size(); i++) {
		Moments m = moments(shape[i], true);
		double hu[cols];
		HuMoments(m, hu);

		svm_node sample[cols+1];
		for (int j=0; j<cols; j++) {
			sample[j].index = j+1;
			sample[j].value = -1 + 2.*(hu[j]-minScaleFactors_[j])/(maxScaleFactors_[j] - minScaleFactors_[j]);
		}
		sample[cols].index = -1;

		int res = svm_predict_probability(svmModel_, sample, pred_prob);
		double wyn_prob=0;
		for (int j=0; j<staticLabelsData_.size(); j++) {
			if (svm_labels[j] == res) {
				wyn_prob = pred_prob[j];
				break;
			}
		}

		if (wyn_prob > 0.5) {
			if (staticGestures_[i] != res) {
				if (staticGestures_[i] != -1) {
					end_event = new StaticEndEvent(i, staticGestures_[i]);
					EventManager::getInstance().sendEvent(end_event);
					delete end_event;
				}
				staticGestures_[i] = res;
				begin_event = new StaticBeginEvent(i, res);
				EventManager::getInstance().sendEvent(begin_event);
				delete begin_event;
			}

		}
		else {
			if (staticGestures_[i] != -1) {
				end_event = new StaticEndEvent(i, staticGestures_[i]);
				EventManager::getInstance().sendEvent(end_event);
				delete end_event;
				staticGestures_[i] = -1;
			}
		}
	}
	delete [] svm_labels;
	delete [] pred_prob;
}
